import Cropper from 'cropperjs';
import { cloneElement, FC, HTMLProps, isValidElement, useEffect, useRef, useState } from 'react';
import classnames from 'classnames';

import 'cropperjs/dist/cropper.css';

import './style/index.less';

import {
  RotateLeftOutlined,
  RotateRightOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
  SyncOutlined,
} from '@ant-design/icons';

interface CropImgDefaultOptions {
  scaleX?: number;
  scaleY?: number;
  enable?: boolean;
  zoomTo?: number;
  rotateTo?: number;
}

export interface CropImgProps
  extends CropImgDefaultOptions,
    Omit<HTMLProps<HTMLImageElement>, 'data' | 'ref' | 'style'> {
  cropperOptions?: Cropper.Options<HTMLImageElement>;
  onInitialized?: (instance: Cropper) => void;
  height?: number;
}

const CropImg: FC<CropImgProps> = ({
  scaleY,
  scaleX,
  enable,
  zoomTo,
  rotateTo,
  cropperOptions,
  onInitialized,
  src,
  className,
  height,
  ...restProps
}) => {
  const imgRef = useRef<HTMLImageElement>(null);

  const prefixCls = 'crop-img';

  const cropRef = useRef<Cropper | null>(null);

  const toolClassName = `${prefixCls}-operations-operation`;
  const iconClassName = `${prefixCls}-operations-icon`;

  const [, setRotate] = useState(0);

  const [scale, setScale] = useState(1);

  const handleZoomIn = () => {
    setScale((value) => {
      const zoom = value + (value >= 1 ? 1 : 0.1);
      cropRef.current?.zoomTo(zoom);
      return zoom;
    });
  };

  const handleZoomOut = () => {
    setScale((value) => {
      const zoom = value - (value > 1 ? 1 : 0.1);
      cropRef.current?.zoomTo(zoom);
      return zoom;
    });
  };

  const handleRotateRight = () => {
    setRotate((value) => {
      const newRotate = value + 90;
      cropRef.current?.rotateTo(newRotate);
      return newRotate;
    });
  };

  const handleRotateLeft = () => {
    setRotate((value) => {
      const newRotate = value - 90;
      cropRef.current?.rotateTo(newRotate);
      return newRotate;
    });
  };

  const handleReset = () => {
    cropRef.current?.reset();
  };

  const tools = [
    {
      icon: <ZoomInOutlined />,
      onClick: handleZoomIn,
      type: 'zoomIn',
    },
    {
      icon: <ZoomOutOutlined />,
      onClick: handleZoomOut,
      type: 'zoomOut',
      disabled: 0.1 > scale,
    },
    {
      icon: <RotateRightOutlined />,
      onClick: handleRotateRight,
      type: 'rotateRight',
    },
    {
      icon: <RotateLeftOutlined />,
      onClick: handleRotateLeft,
      type: 'rotateLeft',
    },
    {
      icon: <SyncOutlined />,
      onClick: handleReset,
      type: 'reset',
    },
  ];

  const applyDefaultOptions = (): void => {
    if (!cropRef.current) return;

    const cropper = cropRef.current;

    if (enable ?? true) {
      cropper.enable();
    } else {
      cropper.disable();
    }

    cropper.scaleX(scaleX ?? 1);
    cropper.scaleY(scaleY ?? 1);

    if (rotateTo) {
      cropper.rotateTo(rotateTo);
    }

    if (zoomTo && zoomTo > 0) {
      cropper.zoomTo(zoomTo);
    }
  };

  useEffect(() => {
    if (!imgRef.current) return;

    const { ready, crop, zoom } = cropperOptions || {};

    const cropperInstance = new Cropper(imgRef.current, {
      ...cropperOptions,
      ready: (e) => {
        if (e.currentTarget) {
          applyDefaultOptions();
        }
        ready?.(e);
      },
      crop: (e) => {
        setRotate(e.detail.rotate);

        crop?.(e);
      },
      zoom: (e) => {
        setScale(e.detail.ratio);

        zoom?.(e);
      },
    });

    cropRef.current = cropperInstance;

    onInitialized?.(cropperInstance);

    return () => {
      cropperInstance.destroy();
    };
  }, [imgRef]);

  useEffect(() => {
    if (!cropRef.current) return;

    if (src) {
      cropRef.current.reset().clear().replace(src);
    }
  }, [src]);

  return (
    <div>
      <ul className={`${prefixCls}-operations`}>
        {tools.map(({ icon, onClick, type, disabled }) => (
          <li
            className={classnames(toolClassName, {
              [`${prefixCls}-operations-operation-disabled`]: !!disabled,
            })}
            onClick={onClick}
            key={type}
          >
            {isValidElement(icon) ? cloneElement(icon, { className: iconClassName }) : icon}
          </li>
        ))}
      </ul>

      <div
        className={`${prefixCls}-img-wrapper`}
        style={{
          height: height,
        }}
      >
        <img
          alt="img"
          crossOrigin="anonymous"
          {...restProps}
          src={src}
          style={{ opacity: 0, width: '100%' }}
          ref={imgRef}
        />
      </div>
    </div>
  );
};

export default CropImg;
